package ar.fi.uba.celdas.ambiente.gui;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;

public abstract class HWACanvas extends Canvas {
	
	private static final long serialVersionUID = 1L;
	protected Dimension viewportSize = null;
	private boolean continueLoop = true;
	private boolean displayFPS = false;
	
	public HWACanvas() {}
		
	protected void init(){
		try{
		    Display.setParent(this);
		    Display.create();
		                	
		    //Keyboard
		    Keyboard.create();
	
		    //Mouse
		    Mouse.setGrabbed(false);
		    Mouse.create();
	
		    //OpenGL
		    resizeGL(getWidth(), getHeight());
		    initGL();		    
		    
		    //listener de redimensionamiento de ventana
		    addComponentListener(new ComponentListener() {
				
				@Override
				public void componentShown(ComponentEvent e) {}
				
				@Override
				public void componentResized(ComponentEvent e) {
					viewportSize = getSize();
				}
				
				@Override
				public void componentMoved(ComponentEvent e) {}
				
				@Override
				public void componentHidden(ComponentEvent e) {}
			});
		    
		}catch(LWJGLException e){
			Logger.getLogger(getClass().getName())
					.log(Level.SEVERE, e.getMessage());
		}
	}
	
	/**
	 * Inicia el loop del widget
	 * Se debe llamar después de que Vista3D sea visible
	 */
	public void start() {
		init();
		
		loop();

		destroy();
	}
	
	/**
	 * Se debe llamar antes de destruir el contenedor de este widget;
	 */
	public synchronized void stop(){
		continueLoop = false;
	}
	
	protected void loop() {
		long startTime = System.currentTimeMillis() + 5000;
		long fps = 0;

		while (continueLoop) {
			synchronized (this) {
				if (viewportSize != null){
					resizeGL(viewportSize.width, viewportSize.height);
					viewportSize = null;
				}
				
				redraw();
				
				Display.update();
				
				if (displayFPS){
					if (startTime > System.currentTimeMillis()) {
						fps++;
					} else {
						long timeUsed = 5000 + (startTime - System.currentTimeMillis());
						startTime = System.currentTimeMillis() + 5000;
						System.out.println(fps + " frames in " + timeUsed / 1000f + " seconds = "
								+ (fps / (timeUsed / 1000f)));
						fps = 0;
					}
				}
			}
		}
	}	
	
	public void setDisplayFPS(boolean displayFPS) {
		this.displayFPS = displayFPS;
	}
	
	protected void destroy() {
		Display.destroy();
	}
	
	protected abstract void redraw();

	protected abstract void initGL(); 
	 
	protected void resizeGL(int width, int height) {
		glViewport(0, 0, width, height);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(60.0f, (float)width/(float)height, 0.10f, 100.0f);
		glMatrixMode(GL_MODELVIEW);
    }
	 

}
